---
description: 'Learn how to implement customer account functionalities in your storefront using the REST APIs. This includes implementing customer registration, login, edit profile, and more.'
addHowToData: true
---

import Tabs from '@theme/Tabs';
import TabItem from '@theme/TabItem';

# How to Implement Customer Profiles

In this document, you’ll learn how to implement customer account functionalities in a storefront.

## Overview

Medusa provides the necessary functionalities and endpoints to allow integrating essential customer features. Customers can create accounts to manage their information and keep track of their orders.

### Scenario

You want to implement the following features in a storefront:

- Customer registration
- Customer login and logout
- Allow customers to reset their password
- Allow customers to manage their basic information and shipping addresses
- Show customers their orders

:::note

You can use Medusa’s Store APIs to achieve more functionalities as well. Check out the [API reference](/api/store/#tag/Customer) to learn more.

:::

---

## Prerequisites

### Medusa Components

It's assumed that you already have a Medusa backend installed and set up. If not, you can follow the [quickstart guide](../../../development/backend/install.mdx) to get started.

It's also assumed you already have a storefront set up. It can be a custom storefront or one of Medusa’s storefronts. If you don’t have a storefront set up, you can install the [Next.js starter storefront](../../../starters/nextjs-medusa-starter.mdx).

### JS Client

This guide includes code snippets to send requests to your Medusa backend using Medusa’s JS Client, among other methods.

If you follow the JS Client code blocks, it’s assumed you already have [Medusa’s JS Client installed](../../../js-client/overview.md) and have [created an instance of the client](../../../js-client/overview.md#configuration).

### Medusa React

This guide also includes code snippets to send requests to your Medusa backend using Medusa React, among other methods.

If you follow the Medusa React code blocks, it's assumed you already have [Medusa React installed](../../../medusa-react/overview.md) and have [used MedusaProvider higher in your component tree](../../../medusa-react/overview.md#usage).

---

## Register a Customer

A customer can register with an email and a password to store and manage their data.

You can register a new customer by sending a request to the [Create a Customer](/api/store/#tag/Customer/operation/PostCustomers) endpoint:

<Tabs groupId="request-type" wrapperClassName="code-tabs">
<TabItem value="client" label="Medusa JS Client" default>

```ts
medusa.customers.create({
  email,
  password,
  first_name,
  last_name,
})
.then(({ customer }) => {
  console.log(customer.id)
})
```

</TabItem>
<TabItem value="medusa-react" label="Medusa React">

```tsx
import { useCreateCustomer } from "medusa-react"

const RegisterCustomer = () => {
  const createCustomer = useCreateCustomer()
  // ...

  const handleCreate = () => {
    // ...
    createCustomer.mutate({
      first_name,
      last_name,
      email,
      password,
    })
  }

  // ...
  
  return (
    <form>
      {/* Render form */}
    </form>
  )
}

export default RegisterCustomer
```

</TabItem>
<TabItem value="fetch" label="Fetch API">

```ts
fetch(`<BACKEND_URL>/store/customers`, {
  method: "POST",
  credentials: "include",
  headers: {
    "Content-Type": "application/json",
  },
  body: JSON.stringify({
    email,
    password,
    first_name,
    last_name,
  }),
})
.then((response) => response.json())
.then(({ customer }) => {
  console.log(customer.id)
})
```

</TabItem>
</Tabs>

This request requires the following body parameters:

- `email`: An email used to log in after registration. This email must be unique. You can check if an email is unique using the “[Check if email exists](/api/store/#tag/Auth/operation/GetAuthEmail)” endpoint.
- `password`: A password used to log in after registration.
- `first_name`: The customer’s first name.
- `last_name`: The customer’s last name.

This request also accepts optional body parameters, which you can check out in the [API reference](/api/store/#tag/Customer/operation/PostCustomers).

It returns the created customer object in the response.

---

## Log in a Customer

A customer can log in to your store to manage their data and make purchases using their account.

You can log in a customer into your store by sending a request to the [Customer Login](/api/store/#tag/Auth/operation/PostAuth) endpoint:

<Tabs groupId="request-type" wrapperClassName="code-tabs">
<TabItem value="client" label="Medusa JS Client" default>

```ts
medusa.auth.authenticate({
  email,
  password,
})
.then(({ customer }) => {
  console.log(customer.id)
})
```

</TabItem>
<TabItem value="fetch" label="Fetch API">

```ts
fetch(`<BACKEND_URL>/store/auth`, {
  method: "POST",
  credentials: "include",
  headers: {
    "Content-Type": "application/json",
  },
  body: JSON.stringify({
    email,
    password,
  }),
})
.then((response) => response.json())
.then(({ customer }) => {
  console.log(customer.id)
})
```

</TabItem>
</Tabs>

This request requires the body parameters `email` and `password`. It returns the customer object in the response.

If you’re using the Medusa JS Client, the customer’s session will already be set and used in all future requests.

However, if you’re using the Fetch API, you must include the option `credentials` with the value `include` to make sure all future requests are authenticated.

---

## Log out a Customer

You can log out a customer by sending a request to the [Customer Logout](/api/store/#tag/Auth/operation/DeleteAuth) endpoint:

<Tabs groupId="request-type" wrapperClassName="code-tabs">
<TabItem value="client" label="Medusa JS Client" default>

```ts
medusa.auth.deleteSession()
.then(() => {
  // success
})
```

</TabItem>
<TabItem value="fetch" label="Fetch API">

```ts
fetch(`<BACKEND_URL>/store/auth`, {
  method: "DELETE",
  credentials: "include",
})
.then(() => {
  // success
})
```

</TabItem>
</Tabs>

If this request is successful, the customer’s session will be deleted and they’ll be logged out.

---

## Reset Password

Customers might need to reset their password in case they forget it. To reset a customer’s password, you need to implement two steps.

### Step 1: Request Password Reset

The customer must first enter their account’s email. Then, if an account with that email address exists, an email will be sent to that email address with a link that points the customer to step 2.

You can request to reset a customer’s password by sending a request to the [Request Password Reset](/api/store/#tag/Customer/operation/PostCustomersCustomerPasswordToken) endpoint:

<Tabs groupId="request-type" wrapperClassName="code-tabs">
<TabItem value="client" label="Medusa JS Client" default>

```ts
medusa.customers.generatePasswordToken({
  email,
})
.then(() => {
  // successful
})
.catch(() => {
  // failed
})
```

</TabItem>
<TabItem value="fetch" label="Fetch API">

```ts
fetch(`<BACKEND_URL>/store/customers/password-token`, {
  method: "POST",
  credentials: "include",
  headers: {
    "Content-Type": "application/json",
  },
  body: JSON.stringify({
    email,
  }),
})
.then(() => {
  // successful
})
.catch(() => {
  // failed
})
```

</TabItem>
</Tabs>

This request requires the body parameter `email`. Its value must be the email associated with the customer’s account.

If the request has been processed successfully, it returns a `204` status code in the response. In case it fails, an error will be thrown.

:::note

If the customer doesn’t receive an email after this request, make sure that you’ve set up a Notification provider like [SendGrid](../../../plugins/notifications/sendgrid.mdx) successfully. You also need to add a subscriber that handles the [customer.password_reset](../../../development/events/events-list.md#customer-events) event and sends the email.

:::

### Step 2: Verify and Reset Password

After the first step, the customer should receive an email with a link to a page in the storefront. This page should accept a `token` query parameter. Then, the customer should be prompted to enter their email and password.

You can then reset the customer’s password to the new password they enter by sending a request to the [Reset Password](/api/store/#tag/Customer/operation/PostCustomersResetPassword) endpoint:

<Tabs groupId="request-type" wrapperClassName="code-tabs">
<TabItem value="client" label="Medusa JS Client" default>

```ts
medusa.customers.resetPassword({
  email,
  password,
  token,
})
.then(({ customer }) => {
  console.log(customer.id)
})
```

</TabItem>
<TabItem value="fetch" label="Fetch API">

```ts
fetch(`<BACKEND_URL>/store/customers/password-reset`, {
  method: "POST",
  credentials: "include",
  headers: {
    "Content-Type": "application/json",
  },
  body: JSON.stringify({
    email,
    password,
    token,
  }),
})
.then((response) => response.json())
.then(({ customer }) => {
  console.log(customer.id)
})
```

</TabItem>
</Tabs>

This request requires the following body parameters:

- `email`: The email of the customer. This must be the email associated with the account.
- `password`: The new password the customer wants to use for their account.
- `token`: The token passed as a query into the page.

If successful, this request returns the customer object in the response.

---

## Edit a Customer’s Info

A logged-in customer can edit their info, such as their first name or email address.

You can edit a customer’s info using the [Update Customer](/api/store/#tag/Customer/operation/PostCustomersCustomer) endpoint:

<Tabs groupId="request-type" wrapperClassName="code-tabs">
<TabItem value="client" label="Medusa JS Client" default>

```ts
medusa.customers.update({
  first_name,
})
.then(({ customer }) => {
  console.log(customer.id)
})
```

</TabItem>
<TabItem value="medusa-react" label="Medusa React">

```tsx
import { useUpdateMe } from "medusa-react"

const UpdateCustomer = () => {
  const updateCustomer = useUpdateMe()
  // ...

  const handleUpdate = () => {
    // ...
    updateCustomer.mutate({
      id: customer_id,
      first_name,
    })
  }

  // ...
  
  return (
    <form>
      {/* Render form */}
    </form>
  )
}

export default UpdateCustomer
```

</TabItem>
<TabItem value="fetch" label="Fetch API">

```ts
fetch(`<BACKEND_URL>/store/customers/me`, {
  method: "POST",
  credentials: "include",
  headers: {
    "Content-Type": "application/json",
  },
  body: JSON.stringify({
    first_name,
  }),
})
.then((response) => response.json())
.then(({ customer }) => {
  console.log(customer.id)
})
```

</TabItem>
</Tabs>

This request accepts any of the customer’s details that should be updated as body parameters. In the example above, the `first_name` of the customer is updated. You can check out the [API reference](/api/store/#tag/Customer/operation/PostCustomersCustomer) for a full list of accepted body parameters.

It returns in the response the updated customer object.

---

## Manage Shipping Addresses

A logged-in customer uses their shipping addresses during the checkout process. They can have more than one shipping address, and they can choose one of them when placing an order.

:::tip

The customer object returned in the requests mentioned in this document include a `shipping_addresses` property. It’s an array of the customer’s shipping addresses. You can access it to display the customer’s shipping addresses.

:::

### Add a Shipping Address

You can add a shipping address to a customer’s account by sending a request to the [Add a Shipping Address](/api/store/#tag/Customer/operation/PostCustomersCustomerAddresses) endpoint:

<Tabs groupId="request-type" wrapperClassName="code-tabs">
<TabItem value="client" label="Medusa JS Client" default>

```ts
medusa.customers.addresses.addAddress({
  address: {
    first_name,
    last_name,
    address_1,
    city,
    country_code,
    postal_code,
    phone,
    company,
    address_2,
    province,
    metadata,
  },
})
.then(({ customer }) => {
  console.log(customer.id)
})
```

</TabItem>
<TabItem value="fetch" label="Fetch API">

```ts
fetch(`<BACKEND_URL>/store/customers/me/addresses`, {
  method: "POST",
  credentials: "include",
  headers: {
    "Content-Type": "application/json",
  },
  body: JSON.stringify({
    address: {
      first_name,
      last_name,
      address_1,
      city,
      country_code,
      postal_code,
      phone,
      company,
      address_2,
      province,
      metadata,
    },
  }),
})
.then((response) => response.json())
.then(({ customer }) => {
  console.log(customer.id)
})
```

</TabItem>
</Tabs>

This request requires an `address` object as a body parameter. The `address` object must have the following properties:

- `first_name`: The first name associated with the shipping address
- `last_name`: The last name associated with the shipping address
- `address_1`: The first address line of the shipping address.
- `city`: The city of the shipping address.
- `country_code`: The 2 character ISO code of the country in lower case.
- `postal_code`: The postal code of the shipping address

It also accepts other optional body parameters, which you can learn more about in the [API reference](/api/store/#tag/Customer/operation/PostCustomersCustomerAddresses).

This request returns the updated customer object in the response.

### Edit a Shipping Address

You can edit a customer’s shipping address using the [Update a Shipping Address](/api/store/#tag/Customer/operation/PostCustomersCustomerAddressesAddress) endpoint:

<Tabs groupId="request-type" wrapperClassName="code-tabs">
<TabItem value="client" label="Medusa JS Client" default>

```ts
medusa.customers.addresses.updateAddress(addressId, {
  first_name,
})
.then(({ customer }) => {
  console.log(customer.id)
})
```

</TabItem>
<TabItem value="fetch" label="Fetch API">

```ts
fetch(`<BACKEND_URL>/store/customers/me/addresses/${addressId}`,
  {
    method: "POST",
    credentials: "include",
    headers: {
      "Content-Type": "application/json",
    },
    body: JSON.stringify({
      first_name,
    }),
  }
)
.then((response) => response.json())
.then(({ customer }) => {
  console.log(customer.id)
})
```

</TabItem>
</Tabs>

This request requires the address’s ID as a path parameter. It accepts as a body parameter any of the address’s properties. In the example above, the `first_name` of the shipping address is updated. You can check the [API reference](/api/store/#tag/Customer/operation/PostCustomersCustomerAddressesAddress) for all the available body parameters.

This request returns the updated customer object in the response.

### Delete a Shipping Address

You can delete a shipping address by sending a request to the [Delete an Address](/api/store/#tag/Customer/operation/DeleteCustomersCustomerAddressesAddress) endpoint:

<Tabs groupId="request-type" wrapperClassName="code-tabs">
<TabItem value="client" label="Medusa JS Client" default>

```ts
medusa.customers.addresses.deleteAddress(addressId)
.then(({ customer }) => {
  console.log(customer.id)
})
```

</TabItem>
<TabItem value="fetch" label="Fetch API">

```ts
fetch(`<BACKEND_URL>/store/customers/me/addresses/${addressId}`,
  {
    method: "DELETE",
    credentials: "include",
  }
)
.then((response) => response.json())
.then(({ customer }) => {
  console.log(customer.id)
})
```

</TabItem>
</Tabs>

This request requires the address’s ID as a path parameter. It returns in the response the updated customer object.

---

## Retrieve a Customer’s Orders

Logged-in customers can see their orders along with the orders’ details.

You can retrieve a customer’s orders by sending a request to the [List Orders](/api/store/#tag/Customer/operation/GetCustomersCustomerOrders) endpoint:

<Tabs groupId="request-type" wrapperClassName="code-tabs">
<TabItem value="client" label="Medusa JS Client" default>

```ts
medusa.customers.listOrders()
.then(({ orders, limit, offset, count }) => {
  console.log(orders)
})
```

</TabItem>
<TabItem value="medusa-react" label="Medusa React">

```tsx
import { useCustomerOrders } from "medusa-react"
import { Order } from "@medusajs/medusa"

const Orders = () => {
  // refetch a function that can be used to
  // re-retrieve orders after the customer logs in
  const { orders, isLoading, refetch } = useCustomerOrders()

  return (
    <div>
      {isLoading && <span>Loading orders...</span>}
      {orders?.length && (
        <ul>
          {orders.map((order: Order) => (
            <li key={order.id}>{order.display_id}</li>
          ))}
        </ul>
      )}
    </div>
  )
}

export default Orders
```

</TabItem>
<TabItem value="fetch" label="Fetch API">

```ts
fetch(`<BACKEND_URL>/store/customers/me/orders`, {
  credentials: "include",
})
.then((response) => response.json())
.then(({ orders, limit, offset, count }) => {
  console.log(orders)
})
```

</TabItem>
</Tabs>

This request doesn’t require any path or query parameters. You can, however, send optional query parameters used for filters, pagination, and sorting. You can learn more in the [API reference](/api/store/#tag/Customer/operation/GetCustomersCustomerOrders).

It returns the following data in the response:

- `orders`: An array of orders.
- `limit`: The maximum number of orders that can be returned in the request.
- `offset`: The number of orders skipped in the result.
- `count`: The total number of orders available.

:::info

You can learn more about pagination in the [API reference](/api/store/#section/Pagination).

:::